/*
 * Copyright 2012 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package net;

import java.lang.reflect.InvocationTargetException;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.handler.codec.http.DefaultHttpRequest;
import org.jboss.netty.handler.codec.http.HttpHeaders;
import org.jboss.netty.handler.codec.http.HttpMethod;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.jboss.netty.handler.codec.http.HttpResponse;
import org.jboss.netty.handler.codec.http.HttpVersion;
import org.jboss.netty.util.CharsetUtil;

import database.DBMongo;

import system.Config;
import system.L;
import util.ChannelBufferUtil;

public class VerifyHandler extends SimpleChannelUpstreamHandler {
	
	public String receipt;
	public ClientContext client;
	public String guid;
	public String uname;
	public DBMongo db;
	
	public boolean _received;

    @Override
    public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) {
    	if (!_received) {
    		notifyClient(true);
    		_received = true;
    	}
    	L.debug(e.getChannel().getRemoteAddress()  + " close");
    }
    
    @Override
    public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
    	L.debug(e.getChannel().getRemoteAddress()  + " connect");
        // Prepare the HTTP request.
        HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, Config.VERIFY_PATH);
//        request.setHeader(HttpHeaders.Names.HOST, Config.VERIFY_HOST);
        request.setHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE);
//        request.setHeader(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP);
        ChannelBuffer content = ChannelBuffers.copiedBuffer(receipt, CharsetUtil.UTF_8);
        request.setContent(content);
        request.setHeader(HttpHeaders.Names.CONTENT_LENGTH, content.readableBytes());
        // Send the HTTP request.
        e.getChannel().write(request);
    }
    
    public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
    	Channel channel = e.getChannel();
    	channel.close();
    	L.debug(e.getChannel().getRemoteAddress()  + " disconnect");
    }

    @Override
    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
    	HttpResponse response = (HttpResponse) e.getMessage();
    	
    	L.debug("STATUS: " + response.getStatus());
    	L.debug("VERSION: " + response.getProtocolVersion());
    	
//    	if (!response.getHeaderNames().isEmpty()) {
//    		for (String name: response.getHeaderNames()) {
//    			for (String value: response.getHeaders(name)) {
//    				System.out.println("HEADER: " + name + " = " + value);
//    			}
//    		}
//    		System.out.println();
//    	}
    	ChannelBuffer content = response.getContent();
    	if (content.readable()) {
    		String json = content.toString(CharsetUtil.UTF_8);
    		L.info("CONTENT {" + json + "} END OF CONTENT");
    		_received = true;
    		notifyClient(checkResult(json));
    	} else {
    		notifyClient(true);
    	}
    }
    
    private boolean checkResult(String json) {
    	if (json.indexOf(Config.PRODUCT_ID) == -1) {
    		L.info("error product id");
    		return false;
    	}
    	if (json.indexOf("\"status\":0") != -1)
    		return true;
    	if (json.indexOf("\"status\": 0") != -1)
    		return true;    	
    	return false;
    }
    
    private void notifyClient(boolean success) {
    	if (client!= null && client.syner._channel.isConnected()){
    		L.info("guid:" + guid + ", ip:" + client.syner._channel.getRemoteAddress()
    				+ ", purchase result: " + success);
        	ChannelBuffer buf = client.syner.prepareQueryResult();
        	ChannelBufferUtil.writeBool(buf, success);
        	client.syner.sendMsg(true);
        	if (success) {
        		db.addReceipt(guid, receipt, uname);
        	}
        	client = null;
    	}
    }
    
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
    	try {
    		L.error(e.toString());
    		Throwable cause = e.getCause();
    		StackTraceElement[] trace; 
    		if (cause instanceof InvocationTargetException) {
    			InvocationTargetException ite = (InvocationTargetException)cause;
    			L.error(ite.getTargetException().toString());
    			trace = ite.getTargetException().getStackTrace();
    		} else {
    			trace = cause.getStackTrace();
    		}
    		
    		for (StackTraceElement st: trace) {
    			L.error(st.toString());
    		}
    	} catch (Exception ept) {
    		
    	} finally {
    		e.getChannel().close();
    	}
    }
    
}
